package com.xsy.req.utils;

import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.http.Method;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.Cache;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.stereotype.Component;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

/**
 * 功能描述：获取销售易信息工具类
 */
@Component
public class CrmApiUtils {
    private final static Logger logger = LoggerFactory.getLogger(CrmApiUtils.class);

    @Value("${xsy.userName}")
    private String username = "v-kuangzk@neocrm.com";
    @Value("${xsy.password}")
    private String password = "Kzk202403";
    @Value("${xsy.securityCode}")
    private String securityCode = "xqcIkwn4";
    @Value("${xsy.clientId}")
    private String clientId = "48d0cc503b721322e4e618b87b9f81a8";
    @Value("${xsy.clientSecret}")
    private String clientSecret = "ea1a5bd9e522965a5d829c867ac8a9b8";
    @Value("${xsy.domain}")
    private String domain = "https://api-p05.xiaoshouyi.com";
    private String LOGIN_URL = "https://login.xiaoshouyi.com/auc/oauth2/token"; // 获取销售易token接口
    private String QUERY_API_URI = "/rest/data/v2/query"; // 查询接口
    private String API_V20_URL = "/rest/data/v2.0/xobjects";
    private String xoqlQuery = "/rest/data/v2.0/query/xoql"; // xoql查询接口

    private Cache cacheApi;

    public CrmApiUtils() {
        ConcurrentMapCacheManager cacheManager = new ConcurrentMapCacheManager();
        cacheApi = cacheManager.getCache("default");
    }


    public void queryUserByName() throws UnsupportedEncodingException {
        String sql = "select id,name from user where name = '张新同1'";
        JSONObject jsonObject = queryOne(sql);
        System.out.println("jsonObject = " + jsonObject);

        //sendPost();
    }


    public void setOwnerId() throws UnsupportedEncodingException {

        // 查询 客户拓展组 排除用户 顾燕 的其他用户数据
        String sql = "select id,name from user where dimDepart = 3215383090859334 and id != 3206437788945673";
        JSONArray userList = query(sql);

        /*
            ownerId 就是上面集合数据中的 id
            注意：对上面的用户进行轮询分配 例如只有两个用户 上一次最后分配到的用户是 '用户一'  那下次执行分配应该从 '用户二' 开始进行分配
         */

        sql = "select id,name from user where status = 1 and assignBdAccount__c in (1,2) order by createdAt";
        JSONArray tableData = getTableData(sql);
        System.out.println("tableData = " + tableData);
    }

    /**
     * 新增线索
     */
    public void addLead() throws UnsupportedEncodingException {
        // 新增必要的参数
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("entityType", "11010001100001"); // 业务类型

        // 模拟参数
        jsonObject.put("name", "测试新增销售线索-01"); // 业务类型
        jsonObject.put("companyName", "测试公司名称"); // 公司名称
        jsonObject.put("country__c", 45); // 国家/地区  默认：中国
        jsonObject.put("fState", 2); // 省
        jsonObject.put("fCity", 2); //城市

        CrmApiUtils crmApiUtils = new CrmApiUtils();

        // 第一个参数: 需要操作的对象  第二个参数: 数据
        //ResultVo insert = crmApiUtils.insert("lead", jsonObject);
        //System.out.println("lead = " + insert.getCode());
        //System.out.println("lead = " + insert.getMsg());
    }


    /**
     * 修改机会
     */
    public void updateOpportunity() throws UnsupportedEncodingException {
        /*
            测试修改机会 （机会名称为 '测试-12' 的数据） 下面的字段名称可以在系统管理后台查看
            projectCode__c 项目编码 （文本类型）
            ProjectPhase__c  项目阶段 （单选 1：售前 2：交付 3：质保）
            projectStatus__c 项目状态  (单选：1:进行中  2： penging)
            PMOAAccount__c  项目经理OA账号 （文本类型）
            PMName__c  项目经理姓名（文本类型）
         */
        CrmApiUtils crmApiUtils = new CrmApiUtils();
        JSONObject jsonObject = new JSONObject();

        // 新增、修改必要的两个参数

        // 1: id
        long opportunityId = 3230799975107967L;
        jsonObject.put("id", opportunityId); // 线索id

        // PMS需要修改的参数
        jsonObject.put("opportunityName", "测试-12"); // 测试修改 业务机会名称
        jsonObject.put("projectCode__c", ""); // 项目编码
        jsonObject.put("ProjectPhase__c", 1); // 项目阶段

        // 第一个参数: 需要操作的对象  第二个参数: 数据
        ResultVo update = crmApiUtils.update("opportunity", jsonObject);
        System.out.println("update = " + update);
    }


    /**
     * 获取表数据
     * @param xoql 最大一次支持 3000 条
     * @return
     */
    public JSONArray getTableData(String xoql) {
        JSONArray arrays = new JSONArray();
        getAllDatasForXoql(xoql, arrays, 0);
        logger.info("总数量：" + arrays.size());
        return arrays;
    }

    private void getAllDatasForXoql(String xoql, JSONArray arrays, int num) {
        StringBuilder sqlBulder = new StringBuilder(xoql);
        sqlBulder.append(" order by id desc ");
        sqlBulder.append(" LIMIT ");
        sqlBulder.append(3000);
        sqlBulder.append(" OFFSET ");
        sqlBulder.append(num);
        HttpResponse execute = HttpUtil.createPost(domain + xoqlQuery)
                .form("xoql", sqlBulder.toString())
                .form("useSimpleCode", true)
                .header("Authorization", "Bearer " + getToken())
                .execute();
        JSONObject result = JSONObject.parseObject(execute.body());
        Integer code = result.getInteger("code");
        String msg = result.getString("msg");
        if (code != 200) {
            // 处理 token 过期
            if (msg.equals("无效的access token") || code == 1020008) {
                System.out.println("重新获取 token ");
                cacheApi.put("tokenInfo", null);
                getAllDatasForXoql(xoql, arrays, num);
            } else {
                throw new RuntimeException("查询数据失败：" + msg);
            }
        }
        JSONObject data = result.getJSONObject("data");
        Integer count = data.getInteger("count");
        arrays.addAll(data.getJSONArray("records"));
        if (count < 3000) {
            return;
        }
        getAllDatasForXoql(xoql, arrays, num + 3000);
    }

    public Long getTotalSize(String xoql) {
        HttpResponse execute = HttpUtil.createPost(domain + xoqlQuery).form("xoql", xoql)
                .header("Authorization", "Bearer " + getToken())
                .execute();
        JSONObject result = JSONObject.parseObject(execute.body());
        Integer code = result.getInteger("code");
        String msg = result.getString("msg");
        if (code != 200) {
            // 处理 token 过期
            if (msg.equals("无效的access token") || code == 1020008) {
                System.out.println("重新获取 token ");
                cacheApi.put("tokenInfo", null);
                return getTotalSize(xoql);
            }
            throw new RuntimeException("查询数据失败：" + msg);
        }
        Long count = result.getJSONObject("data").getLong("totalSize");
        logger.info("数据总量：" + count);
        return count;
    }

    /**
     * 查询一条数据
     * @param sql
     * @return
     * @throws UnsupportedEncodingException
     */
    public JSONObject queryOne(String sql) throws UnsupportedEncodingException {
        sql = sql + " limit 0,1";
        HttpResponse execute = HttpUtil.createGet(domain + QUERY_API_URI + "?q=" + URLEncoder.encode(sql, "UTF-8"))
                .header("xsy-criteria", "10")
                .header("Authorization", "Bearer " + getToken())
                .execute();
        JSONObject result = JSONObject.parseObject(execute.body());
        System.out.println("result = " + result);
        Integer code = result.getInteger("code");
        String msg = result.getString("msg");
        if (code != 200) {
            // 处理 token 过期
            if (msg.equals("无效的access token") || code == 1020008) {
                System.out.println("重新获取 token ");
                cacheApi.put("tokenInfo", null);
                return queryOne(sql);
            }
            throw new RuntimeException("查询数据失败：" + msg);
        }
        JSONArray jsonArray = result.getJSONObject("result").getJSONArray("records");
        if (jsonArray.size() <= 0) {
            return null;
        }
        JSONObject object = jsonArray.getJSONObject(0);
        return object;
    }

    /**
     * 查询数据 最大一次支持 300 条
     * @param sql
     * @return
     * @throws UnsupportedEncodingException
     */
    public JSONArray query(String sql) throws UnsupportedEncodingException {
        sql = sql + " limit 0,300";
        HttpResponse execute = HttpUtil.createGet(domain + QUERY_API_URI + "?q=" + URLEncoder.encode(sql, "UTF-8"))
                .header("xsy-criteria", "10")
                .header("Authorization", "Bearer " + getToken())
                .execute();
        JSONObject result = JSONObject.parseObject(execute.body());
        Integer code = result.getInteger("code");
        String msg = result.getString("msg");
        if (code != 200) {
            // 处理 token 过期
            if (msg.equals("无效的access token") || code == 1020008) {
                System.out.println("重新获取 token ");
                cacheApi.put("tokenInfo", null);
                return query(sql);
            }
            throw new RuntimeException("查询数据失败：" + msg);
        }
        JSONArray jsonArray = result.getJSONObject("result").getJSONArray("records");
        return jsonArray;
    }

    /**
     * 发送 post  请求
     * @return
     * @throws UnsupportedEncodingException
     */
    public ResultVo sendPost() throws UnsupportedEncodingException {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("key", "value");

        String requestUrl = domain + "/rest/data/v2.0/scripts/api/pms/projectBudget";
        HttpResponse execute = HttpUtil.createRequest(Method.POST, requestUrl)
                .header("Authorization", "Bearer " + getToken())
                .body(JSON.toJSONString(jsonObject))
                .execute();

        JSONObject result = JSONObject.parseObject(execute.body());
        Integer code = result.getInteger("code");
        String msg = result.getString("msg");
        if (code != 200) {
            // 处理 token 过期
            if (msg.equals("无效的access token") || code == 1020008) {
                System.out.println("重新获取 token ");
                cacheApi.put("tokenInfo", null);
                return sendPost();
            }
            return ResultVo.error("修改数据失败" + msg);
        }
        return ResultVo.success();
    }


    /**
     * 修改数据
     * @param apikey
     * @param jsonObject
     * @return
     * @throws UnsupportedEncodingException
     */
    public ResultVo update(String apikey, JSONObject jsonObject) throws UnsupportedEncodingException {
        StringBuilder sb = new StringBuilder();
        sb.append("{\"data\":").append(JSON.toJSONString(jsonObject)).append("}");

        String requestUrl = domain + API_V20_URL + "/" + apikey + "/" + jsonObject.get("id");
        HttpResponse execute = HttpUtil.createRequest(Method.PATCH, requestUrl)
                .header("xsy-criteria", "10")
                .header("Authorization", "Bearer " + getToken())
                .body(sb.toString())
                .execute();

        JSONObject result = JSONObject.parseObject(execute.body());
        Integer code = result.getInteger("code");
        String msg = result.getString("msg");
        if (code != 200) {
            // 处理 token 过期
            if (msg.equals("无效的access token") || code == 1020008) {
                System.out.println("重新获取 token ");
                cacheApi.put("tokenInfo", null);
                return update(apikey, jsonObject);
            }
            return ResultVo.error("修改数据失败" + msg);
        }
        return ResultVo.success();
    }

    /**
     * 新增数据
     * @param apikey
     * @param jsonObject
     * @return
     * @throws UnsupportedEncodingException
     */
    public ResultVo insert(String apikey, JSONObject jsonObject) throws UnsupportedEncodingException {
        StringBuilder sb = new StringBuilder();
        sb.append("{\"data\":").append(JSON.toJSONString(jsonObject)).append("}");

        String requestUrl = domain + API_V20_URL + "/" + apikey;
        HttpResponse execute = HttpUtil.createPost(requestUrl)
                .header("xsy-criteria", "10")
                .header("Authorization", "Bearer " + getToken())
                .body(sb.toString())
                .execute();

        JSONObject result = JSONObject.parseObject(execute.body());
        Integer code = result.getInteger("code");
        String msg = result.getString("msg");
        if (code != 200) {
            // 处理 token 过期
            if (msg.equals("无效的access token") || code == 1020008) {
                System.out.println("重新获取 token ");
                cacheApi.put("tokenInfo", null);
                return insert(apikey, jsonObject);
            }
            return ResultVo.error("新增数据失败: " + msg);
        }
        // 获取返回的主键id
        JSONObject resultData = result.getJSONObject("data");
        return ResultVo.success(resultData.get("id"));
    }

    // 模拟token过期
    public void setToken() {
        JSONObject jsonObject = cacheApi.get("tokenInfo", JSONObject.class);
        String accessToken = jsonObject.getString("access_token");
        accessToken += "1";
        jsonObject.put("access_token", accessToken);
        cacheApi.put("tokenInfo", jsonObject);
        System.out.println("jsonObject = " + jsonObject);
    }

    // 清空token
    public String clearToken() {
        if (cacheApi != null) {
            cacheApi.put("tokenInfo", null);
        }
        return "清空token成功";
    }

    public String getToken() {
        JSONObject tokenInfo = cacheApi.get("tokenInfo", JSONObject.class);
        if (tokenInfo != null) {
            String token = tokenInfo.getString("access_token");
            return token;
        }
        logger.info("没有缓存token，开始查询销售易token  =======> ");
        String url = "%s?grant_type=password&client_id=%s&client_secret=%s&username=%s&password=%s%s";
        url = String.format(url, LOGIN_URL, clientId, clientSecret, username, password, securityCode);

        HttpResponse execute = HttpUtil.createGet(url).execute();
        tokenInfo = JSONObject.parseObject(execute.body());
        logger.info("token信息：" + tokenInfo.toJSONString());
        cacheApi.put("tokenInfo", tokenInfo);
        String token = tokenInfo.getString("access_token");
        return token;
    }
}
